home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Tool Chest / Testing & Debugging / Virtual User / Virtual User Current Release / Examples / External Tool Templates / Pascal Tool Template / YourTool.p < prev    next >
Encoding:
Text File  |  1998-06-04  |  21.3 KB  |  907 lines  |  [TEXT/MPS ]

  1. /*
  2.  *    File:        YourTool.p
  3.  *
  4.  *  Note:        We designed this template to work with V.U. 2.0.  If you have a more
  5.  *                recent version of V.U., please look for the current version of this file.
  6.  *
  7.  *                To add functionality to this tool, replace all occurrences of 'YourTool'
  8.  *                and 'YourService' with your own names and supply the corresponding code.
  9.  *
  10.  *    Contains:    V.U. 2.0 External Tool Pascal Template.
  11.  *
  12.  *                This program receives and responsds to Apple Events using the
  13.  *                V.U. 2.0 external tool Interface protocol. 
  14.  *
  15.  *    Written by:    Automation Systems Team, Apple Computer, Inc.
  16.  *
  17.  */
  18.  
  19. PROGRAM YourTool;
  20.  
  21. USES
  22.     Types,
  23.     Memory,
  24.     Packages,
  25.     Errors,
  26.     QuickDraw,
  27.     Fonts,
  28.     Dialogs,
  29.     Windows,
  30.     Menus,
  31.     Events,
  32.     OSEvents,
  33.     Desk,
  34.     DiskInit,
  35.     Resources,
  36.     ToolUtils,
  37.     AppleEvents,
  38.     EPPC,
  39.     GestaltEqu,
  40.     PPCToolbox,
  41.     Processes,
  42.     VUAE;
  43.  
  44. CONST
  45.     kMBarID        = 128;
  46.     kAppleMenu    = 128;
  47.     kFileMenu    = 129;
  48.     kEditMenu    = 130;
  49.     kNumberOfServices = 7;
  50.     
  51. TYPE
  52.     ServiceInfo = RECORD
  53.         serviceName : Str255;
  54.     END;
  55.  
  56. VAR
  57.     hasAE        : BOOLEAN;
  58.     quitting    : BOOLEAN;
  59.     background    : BOOLEAN;
  60.     theMenuBar    : Handle;
  61.     appleMenu    : MenuHandle;
  62.     fileMenu    : MenuHandle;
  63.     editMenu    : MenuHandle;
  64.     theEvent    : EventRecord;    { the current event }
  65.     aeError        : OSErr;        { the most recent apple event error }
  66.     serviceArray: ARRAY[1..kNumberOfServices] OF ServiceInfo;
  67.  
  68.  
  69. PROCEDURE Idling;
  70. {
  71.     We don't do anything while idling. Perhaps we should sing a song?
  72. }
  73. BEGIN
  74. END {Idling};
  75.  
  76.  
  77. PROCEDURE InvokeDA (theMenu: MenuHandle; theItem: LONGINT);
  78. {
  79.     Bring up a desk accessory.
  80. }
  81. VAR
  82.     err    : OSErr;
  83.     da    : Str255;
  84. BEGIN
  85.     GetItem(theMenu, theItem, da);
  86.     err := OpenDeskAcc(da);
  87. END {InvokeDA};
  88.  
  89.  
  90. PROCEDURE MenuCommand (theCmd: LONGINT);
  91. {
  92.     Activate the appropriate menu item.
  93. }
  94. VAR
  95.     menuID    : LONGINT;
  96.     menuItem: LONGINT;
  97.     dontCare: INTEGER;
  98. BEGIN
  99.     menuID := HiWord(theCmd);
  100.     menuItem := LoWord(theCmd);
  101.     CASE menuID OF
  102.         kAppleMenu:
  103.             IF menuItem <> 1 THEN InvokeDA(appleMenu, menuItem)
  104.             ELSE dontCare := Alert(666, NIL);
  105.         kFileMenu: quitting := TRUE;
  106.         kEditMenu: ;
  107.     END;
  108.     HiliteMenu(0);
  109. END {MenuCommand};
  110.  
  111.  
  112. PROCEDURE DispatchMouseDown (theEvent: EventRecord);
  113. {
  114.     Dispatch a mouse down event to the proper handler.
  115. }
  116. VAR
  117.     theWindow    : WindowPtr;
  118. BEGIN
  119.     CASE FindWindow(theEvent.where, theWindow) OF
  120.         inMenuBar: MenuCommand(MenuSelect(theEvent.where));
  121.         inSysWindow: SystemClick(theEvent, theWindow);
  122.         inDrag:
  123.             IF theWindow = FrontWindow THEN
  124.                 DragWindow(theWindow, theEvent.where, screenBits.bounds);
  125.         inContent, inDesk, inGrow, inGoAway: ;
  126.     END;
  127. END {DispatchMouseDown};
  128.  
  129.  
  130. PROCEDURE DispatchKeyDown (theEvent: EventRecord);
  131. {
  132.     Dispatch a key down event to the proper handler. Since typing
  133.     isn't supported, the routine only checks for command key equivalents.
  134. }
  135. VAR
  136.     key    : CHAR;
  137. BEGIN
  138.     key := CHR(BAND(theEvent.message, charCodeMask));
  139.     IF (BAND(theEvent.modifiers, cmdKey ) <> 0) & (theEvent.what = keyDown) THEN
  140.         MenuCommand(MenuKey(key));
  141. END {DispatchKeyDown};
  142.  
  143.  
  144. PROCEDURE ActivateWindow (theWindow: WindowPtr; activating: BOOLEAN);
  145. {
  146.     Gee, we don't have any windows worth activating.
  147. }
  148. BEGIN
  149.     { we don't have any windows to activate }
  150. END {ActivateWindow};
  151.  
  152.  
  153. PROCEDURE UpdateWindow (theWindow: WindowPtr);
  154. {
  155.     Gee, we don't have any windows worth updating.
  156. }
  157. BEGIN
  158.     { we don't have any windows to update }
  159. END {UpdateWindow};
  160.  
  161.  
  162. PROCEDURE DiskInserted (diskInfo: LONGINT);
  163. {
  164.     Handle disk insert errors.
  165. }
  166. VAR
  167.     where    : Point;
  168.     dontCare: OSErr;
  169. BEGIN
  170.     IF HiWord(diskInfo) <> noErr THEN BEGIN
  171.         SetPt(where, 40, 40);
  172.         dontCare := DIBadMount(where, diskInfo);
  173.     END;
  174. END {DiskInserted};
  175.  
  176.  
  177. PROCEDURE DispatchOSEvent (theEvent: EventRecord);
  178. {
  179.     Dispatch OS events.
  180. }
  181. BEGIN
  182.     CASE BAND(BROTL(theEvent.message, 8), $FF) OF
  183.         mouseMovedMessage:
  184.             Idling;
  185.         
  186.         suspendResumeMessage: BEGIN
  187.             background := BAND(theEvent.message, resumeFlag) = 0;
  188.             ActivateWindow(FrontWindow, NOT background);
  189.         END;
  190.     END;
  191. END {DispatchOSEvent};
  192.  
  193.  
  194. PROCEDURE DispatchHighEvent (theEvent: EventRecord);
  195. {
  196.     Send off those Apple Events!
  197. }
  198. BEGIN
  199.     aeError := AEProcessAppleEvent(theEvent);
  200. END {DispatchHighEvent};
  201.  
  202.  
  203. PROCEDURE InitializeServiceArray;
  204. BEGIN
  205.     serviceArray[1].serviceName := 'Initialize';
  206.     serviceArray[2].serviceName := 'Cancel';
  207.     serviceArray[3].serviceName := 'GetToolServices';
  208.     serviceArray[4].serviceName := 'GetToolVersion';
  209.     serviceArray[5].serviceName := 'ServiceSupported';
  210.     serviceArray[6].serviceName := 'Quit';
  211. {    Your services follow.    }
  212.     serviceArray[7].serviceName := 'YourService';
  213. END;
  214.  
  215.  
  216. PROCEDURE ReportError (err: OSErr; where: LONGINT);
  217. {
  218.     Reports an error by way of an Alert dialog. "err" is the error
  219.     code. "where" is an arbitrary (but unique) number indicating
  220.     where in the program the error occurred. Of course, if there
  221.     is no error, this routine does nothing.
  222. }
  223. VAR
  224.     dontCare: INTEGER;
  225.     errStr    : Str255;
  226.     whereStr: Str255;
  227. BEGIN
  228.     IF err <> 0 THEN BEGIN
  229.         NumToString(err, errStr);
  230.         NumToString(where, whereStr);
  231.         ParamText(errStr, whereStr, '', '');
  232.         dontCare := Alert(128, NIL);
  233.     END {--if};
  234. END {ReportError};
  235.  
  236.  
  237. FUNCTION ExtractShortFromAEList(paramList : AEDescList; index : LongInt; VAR result : Integer) : OSErr;
  238.  
  239. VAR
  240.     aeErr        : OSErr;
  241.     paramKeyword: AEKeyword;
  242.     actualType    : DescType;
  243.     actualSize    : Size;
  244.     
  245. BEGIN
  246.     aeErr := AEGetNthPtr(paramList,
  247.                              index,
  248.                              typeShortInteger,
  249.                              paramKeyword,
  250.                              actualType,
  251.                              @result,
  252.                              SIZEOF(INTEGER),
  253.                              actualSize);
  254.     IF aeErr <> noErr THEN
  255.         ReportError(aeErr, 13);
  256.         
  257.     ExtractShortFromAEList := aeErr;
  258. END;
  259.  
  260.  
  261. FUNCTION ExtractStr255FromAEList(paramList : AEDescList; index : LongInt; VAR result : Str255) : OSErr;
  262.  
  263. VAR
  264.     aeErr        : OSErr;
  265.     paramKeyword: AEKeyword;
  266.     actualType    : DescType;
  267.     actualSize    : Size;
  268.     
  269. BEGIN
  270.     aeErr := AEGetNthPtr(paramList,
  271.                              index,
  272.                              typeChar,
  273.                              paramKeyword,
  274.                              actualType,
  275.                              VUStr255ToPtr(result),
  276.                              SIZEOF(Str255),
  277.                              actualSize);
  278.     IF aeErr <> noErr THEN
  279.         ReportError(aeErr, 14)
  280.     ELSE
  281.         result[0] := CHAR(actualSize);
  282.         
  283.     ExtractStr255FromAEList := aeErr;
  284. END;
  285.  
  286.  
  287. PROCEDURE AskForMoreTime( requestedExtraTime : integer; reply : AppleEvent );
  288. VAR
  289.     moreTimeRequestEvent : AppleEvent;
  290.     dummyReply : AppleEvent;
  291.     aeErr : OSErr;
  292.     vuEventId : OSType;
  293.     extraTime : LongInt;
  294.  
  295. BEGIN
  296.     aeErr := AEDuplicateDesc( reply, moreTimeRequestEvent );
  297.     IF( aeErr <> noErr ) THEN
  298.     BEGIN
  299.         ReportError( aeErr, 50 );
  300.     END
  301.     ELSE
  302.     BEGIN
  303.         vuEventId := kVUAEWaitLonger;
  304.         aeErr := AEPutAttributePtr( moreTimeRequestEvent,
  305.                                    keyEventIDAttr,
  306.                                    typeType,
  307.                                    @vuEventId,
  308.                                    SIZEOF( OSType ) );
  309.         IF ( aeErr <> noErr) THEN
  310.         BEGIN
  311.             ReportError( aeErr, 51 );
  312.         END;
  313.  
  314.         extraTime := requestedExtraTime;
  315.         aeErr := AEPutParamPtr( moreTimeRequestEvent, kVUAEWaitAmount, typeMagnitude,
  316.                                 @extraTime, SIZEOF( extraTime ) );
  317.         IF ( aeErr <> noErr ) THEN
  318.         BEGIN
  319.             ReportError( aeErr, 52 );
  320.         END;
  321.         
  322.         aeErr := AESend( moreTimeRequestEvent,
  323.                         dummyReply,
  324.                         kAENoReply + kAENeverInteract,
  325.                         kAENormalPriority,
  326.                         kNoTimeOut,
  327.                         Nil,
  328.                         Nil );
  329.         IF ( aeErr <> noErr ) THEN
  330.         BEGIN
  331.             ReportError( aeErr, 53 );
  332.         END;
  333.         
  334.         aeErr := AEDisposeDesc( moreTimeRequestEvent );
  335.         IF ( aeErr <> noErr) THEN
  336.         BEGIN
  337.             ReportError( aeErr, 54 );
  338.         END;
  339.     END;
  340. END;
  341.  
  342.  
  343. FUNCTION  AEOpenHandler (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  344. {
  345.     Standard (empty) handler for the 'oapp' Apple Event. Our program does
  346.     not need anything special here, so "noErr" can simply be returned.
  347. }
  348. BEGIN
  349.     AEOpenHandler := noErr;
  350. END {AEOpenHandler};
  351.  
  352.  
  353. FUNCTION  AEOpenDocHandler (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  354. {
  355.     Standard (empty) handler for the 'odoc' Apple Event. Our program does
  356.     not have documents, so we ignore this Apple Event.
  357. }
  358. BEGIN
  359.     AEOpenDocHandler := noErr;
  360. END {AEOpenDocHandler};
  361.  
  362.  
  363. FUNCTION  AEQuitHandler (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  364. {
  365.     Standard handler for the 'quit' Apple Event. You must never, ever call
  366.     ExitToShell from within an Apple Event handler. It is certain death
  367.     for you application. Thus, we just set a flag which is examined later
  368.     in the main event loop.
  369. }
  370. BEGIN
  371.     quitting := TRUE;
  372.     AEQuitHandler := noErr;
  373. END {AEQuitHandler};
  374.  
  375.  
  376. FUNCTION  AEPrintHandler (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  377. {
  378.     Standard (empty) handler for the 'pdoc' Apple Event. Our program does
  379.     not have documents, so we ignore this Apple Event.
  380. }
  381. BEGIN
  382.     AEPrintHandler := noErr;
  383. END {AEPrintHandler};
  384.  
  385.  
  386. FUNCTION  VUInitializeHandler (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  387. BEGIN
  388.     VUInitializeHandler := noErr;
  389. END;
  390.  
  391.  
  392. FUNCTION  VUCancelHandler (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  393. BEGIN
  394.     VUCancelHandler := noErr;
  395. END;
  396.  
  397.  
  398. FUNCTION  VUQuitHandler (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  399. BEGIN
  400.     quitting := True;
  401.     VUQuitHandler := noErr;
  402. END;
  403.  
  404.  
  405. FUNCTION  VUVersionHandler (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  406. {
  407.     This Apple Event handler responds to the messages with event class 'v.u.'
  408.     and event id 'vers'. This AppleEvent asks an external tool to respond
  409.     with version information about itself.
  410.     
  411.     The tool name is used by V.U. 2.0 as the name of a tool as shown to a user.
  412.     Thus, this should be something descriptive; e.g., 'Screen Capture Tool'.
  413.     
  414.     The version number is simply a number returned to the caller indicating
  415.     the version of the tool. A V.U. 2.0 script writer could perhaps used this
  416.     information in verifying that the current release of an external tool was
  417.     present.
  418.     
  419.     The version string simply allows more information to be sent by the external
  420.     tool. V.U. 2.0 does not use the version string.
  421.     
  422.     Notice that we must convert the Pascal strings into a format acceptable to
  423.     the Apple Event Manager. Otherwise, the routine simply stuffs values into
  424.     the Apple Event reply using Apple Event Manager routines.
  425. }
  426. VAR
  427.     toolName, shortVersion, longVersion    : Str255;
  428.     aeErr        : OSErr;
  429.     ignore        : OSErr;
  430.     srvcList    : AEDescList;
  431.  
  432. BEGIN
  433.     aeErr := AECreateList( NIL, 0, FALSE, srvcList );
  434.     IF aeErr <> noErr THEN
  435.         BEGIN
  436.             ReportError( aeErr, 3 );
  437.             VUVersionHandler := aeErr;
  438.             EXIT(VUVersionHandler);
  439.         END;
  440.         
  441.     toolName := 'YourToolP';
  442.     aeErr := AEPutPtr( srvcList,
  443.                       1,
  444.                       typeChar,
  445.                       VUStr255ToPtr(toolName),
  446.                       Length(toolName) );
  447.                       
  448.     IF aeErr <> noErr THEN
  449.         BEGIN
  450.             ReportError( aeErr, 4 );
  451.         END
  452.     ELSE
  453.         BEGIN
  454.             shortVersion := '2.0';
  455.             aeErr := AEPutPtr( srvcList,
  456.                               2,
  457.                               typeChar,
  458.                               VUStr255ToPtr(shortVersion),
  459.                               Length(shortVersion) );
  460.             IF aeErr <> noErr THEN
  461.                 BEGIN
  462.                     ReportError( aeErr, 5 );
  463.                 END
  464.             ELSE
  465.                 BEGIN
  466.                     longVersion := '2.0ct by Automation Systems, Apple Computer, Inc.';
  467.                     aeErr := AEPutPtr( srvcList,
  468.                                       3,
  469.                                       typeChar,
  470.                                       VUStr255ToPtr(longVersion),
  471.                                       Length(longVersion) );
  472.                     IF aeErr <> noErr THEN
  473.                         BEGIN
  474.                             ReportError( aeErr, 6 );
  475.                         END
  476.                     ELSE
  477.                         BEGIN
  478.                             aeErr := AEPutKeyDesc( reply,
  479.                                                   kVUAESrvcResults,
  480.                                                   srvcList );
  481.                             IF aeErr <> noErr THEN
  482.                                 BEGIN
  483.                                     ReportError( aeErr, 6 );
  484.                                 END;
  485.                         END;
  486.                 END;
  487.         END;
  488.  
  489.     ignore := AEDisposeDesc(srvcList);
  490.     VUVersionHandler := aeErr;
  491. END;
  492.  
  493.  
  494. FUNCTION  VUHasSrvcHandler (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  495. {
  496.     The routine first extracts the command name from the Apple Event. If the
  497.     command name cannot be extracted for some reason from the Apple Event,
  498.     a standard error reply message is sent back to V.U. 2.0.
  499.     
  500.     The routine simply returns the AppleEvent standard types 'typeTrue' or
  501.     'typeFalse' depending on whether the command name is supported by the
  502.     tool or not. The Apple Event Manager will coerce these standard types
  503.     into an Apple Event Boolean value if necessary (and requested by V.U. 2.0).
  504. }
  505. VAR
  506.     actualSize   : Size;
  507.     aeErr        : OSErr;
  508.     ignore       : OSErr;
  509.     actualType   : DescType;
  510.     paramList     : AEDescList;
  511.     numParams     : LONGINT;
  512.     serviceName  : Str255;
  513.     i            : Integer;
  514.     
  515. BEGIN
  516.     aeErr := AEGetParamDesc(msg,
  517.                             kVUAESrvcParameters,
  518.                             typeAEList,
  519.                             paramList);
  520.                             
  521.     IF aeErr <> noErr THEN
  522.         BEGIN
  523.             ReportError(aeErr, 98);
  524.             VUHasSrvcHandler := aeErr;
  525.             EXIT(VUHasSrvcHandler);
  526.         END;
  527.         
  528.     aeErr := AECountItems(paramList, numParams);
  529.     
  530.     IF aeErr <> noErr THEN
  531.         BEGIN
  532.             ReportError( aeErr, 15 );
  533.         END
  534.     ELSE IF numParams <> 1 THEN
  535.         BEGIN
  536.             aeErr := VUErrorReply(reply, 'Incorrect number of parameters supplied.', errAEWrongParameters );
  537.             IF aeErr <> noErr THEN     
  538.                 BEGIN
  539.                     ReportError( aeErr, 16 );
  540.                 END;
  541.             aeErr := errAEWrongParameters;
  542.         END
  543.     ELSE
  544.         BEGIN
  545.             aeErr := ExtractStr255FromAEList(paramList, 1, serviceName);
  546.             IF aeErr <> noErr THEN
  547.                 BEGIN
  548.                     ReportError(aeErr, 17);
  549.                 END;
  550.         END;
  551.         
  552.     ignore := AEDisposeDesc(paramList);
  553.     IF ignore <> noErr THEN
  554.         BEGIN
  555.             ReportError(aeErr, 8);
  556.         END;
  557.     
  558.     IF aeErr <> noErr THEN
  559.         BEGIN
  560.               ReportError(aeErr, 8);
  561.               aeErr := VUErrorReply(reply, 'No service name parameter supplied!', aeErr);
  562.             VUHasSrvcHandler := aeErr;
  563.             EXIT(VUHasSrvcHandler);
  564.         END;
  565.  
  566.     FOR i := 1 TO kNumberOfServices DO
  567.         BEGIN
  568.             IF relstring(serviceName, serviceArray[i].serviceName, false, true) = 0 THEN
  569.                 BEGIN
  570.                     aeErr := AEPutParamPtr( reply,
  571.                                            kVUAESrvcResults,
  572.                                            typeTrue,
  573.                                            NIL,
  574.                                            0);
  575.                     VUHasSrvcHandler := aeErr;
  576.                     EXIT(VUHasSrvcHandler);
  577.                 END;
  578.         END;
  579.         
  580.     aeErr := AEPutParamPtr( reply,
  581.                            kVUAESrvcResults,
  582.                            typeFalse,
  583.                            NIL,
  584.                            0);
  585.                            
  586.     IF aeErr <> noErr THEN
  587.         BEGIN
  588.             ReportError(aeErr, 9);
  589.         END;
  590.  
  591.     VUHasSrvcHandler := aeErr;
  592.     
  593. END {VUHasSrvcHandler};
  594.  
  595.  
  596. FUNCTION  VUSrvcListHandler (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  597. {
  598.     This Apple Event handler responds to the messages with event class 'v.u.'
  599.     and event id 'cmdl'. This AppleEvent asks an external tool for a list of
  600.     all command names supported by the tool.
  601.     
  602.     Remember that Apple Event Lists are all one (1) based; i.e., indexes
  603.     start from one (not zero).
  604.     
  605.     The first step creates an Apple Event List descriptor. This is followed by
  606.     stuffing each command name into the list, starting at index number one.
  607.     Once the list if filled with the command names, the list itself is inserted
  608.     into the Apple Event reply.
  609. }
  610. VAR
  611.     aeErr : OSErr;
  612.     ignore: OSErr;
  613.     srvcList : AEDescList;
  614.     serviceName  : Str255;
  615.     i : Integer;
  616.  
  617. BEGIN
  618.     aeErr := AECreateList( NIL, 0, FALSE, srvcList );
  619.     IF aeErr <> noErr THEN
  620.     BEGIN
  621.         ReportError( aeErr, 10 );
  622.         VUSrvcListHandler := aeErr;
  623.         EXIT(VUSrvcListHandler);
  624.     END;
  625.  
  626.     FOR i := 1 TO kNumberOfServices DO
  627.     BEGIN
  628.         serviceName := serviceArray[i].serviceName;
  629.         aeErr := AEPutPtr( srvcList,
  630.                           i,
  631.                           typeChar,
  632.                           VUStr255ToPtr(serviceName),
  633.                           Length(serviceName) );
  634.         IF aeErr <> noErr THEN
  635.             BEGIN
  636.                 ReportError( aeErr, 11 );
  637.                 ignore := AEDisposeDesc( srvcList );
  638.                 VUSrvcListHandler := aeErr;
  639.                 EXIT(VUSrvcListHandler);
  640.             END;
  641.     END;
  642.     
  643.     aeErr := AEPutKeyDesc( reply,
  644.                           kVUAESrvcResults,
  645.                           srvcList );
  646.     IF aeErr <> noErr THEN
  647.         BEGIN
  648.             ReportError( aeErr, 12 );
  649.         END;
  650.     
  651.     ignore := AEDisposeDesc(srvcList);
  652.  
  653.     VUSrvcListHandler := aeErr;
  654. END {VUSrvcListHandler};
  655.  
  656.  
  657. FUNCTION  YourService (msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  658. {
  659.     This is an example service which adds two integers.
  660. }
  661. VAR
  662.     aeErr        : OSErr;
  663.     ignore        : OSErr;
  664.     paramList    : AEDescList;
  665.     numParams    : LONGINT;
  666.     leftNumber    : INTEGER;
  667.     rightNumber    : INTEGER;
  668.     result        : INTEGER;
  669.     
  670. BEGIN
  671.     aeErr := AEGetParamDesc(msg,
  672.                             kVUAESrvcParameters,
  673.                             typeAEList,
  674.                             paramList);
  675.                             
  676.     IF aeErr <> noErr THEN
  677.         BEGIN
  678.             ReportError(aeErr, 14);
  679.             YourService := aeErr;
  680.             EXIT(YourService);
  681.         END;
  682.         
  683.     aeErr := AECountItems(paramList, numParams);
  684.     
  685.     IF aeErr <> noErr THEN
  686.         ReportError(aeErr, 15)
  687.     ELSE IF numParams <> 2 THEN
  688.         BEGIN
  689.             aeErr := VUErrorReply(reply, 'Incorrect number of parameters passed to service', errAEWrongParameters);
  690.             IF aeErr <> noErr THEN
  691.                 ReportError(aeErr, 16);
  692.             aeErr := errAEWrongParameters;
  693.         END
  694.     ELSE IF ExtractShortFromAEList( paramList, 1, leftNumber ) <> noErr THEN
  695.         BEGIN
  696.             ReportError(ExtractShortFromAEList( paramList, 1, leftNumber ), 17);
  697.         END
  698.     ELSE IF ExtractShortFromAEList( paramList, 2, rightNumber ) <> noErr THEN
  699.         BEGIN
  700.             ReportError(ExtractShortFromAEList( paramList, 2, rightNumber ), 18);
  701.         END;
  702.                             
  703.     ignore := AEDisposeDesc(paramList);
  704.     
  705.     IF aeErr <> noErr THEN
  706.         BEGIN
  707.             YourService := aeErr;
  708.             EXIT(YourService);
  709.         END;
  710.  
  711.     result := leftNumber + rightNumber;
  712.     
  713.     aeErr := AEPutParamPtr(reply,
  714.                            kVUAESrvcResults,
  715.                            typeShortInteger,
  716.                            @result,
  717.                            SIZEOF(result));
  718.                            
  719.     IF aeErr <> noErr THEN
  720.         BEGIN
  721.             ReportError( aeErr, 19);
  722.             YourService := aeErr;
  723.             EXIT(YourService);
  724.         END;
  725.             
  726.     YourService := aeErr;
  727. END;
  728.  
  729.  
  730. FUNCTION VUServiceHandler(msg, reply: AppleEvent; refCon: LONGINT): OSErr;
  731. VAR
  732.     vuEventClass    : OSType;
  733.     aeErr             : OSErr;
  734.     serviceName     : Str255;
  735.     errStr            : Str255;
  736.     actualType         : DescType;
  737.     actualSize         : Size;
  738.     i                 : Integer;
  739.     found            : boolean;
  740.     
  741. BEGIN
  742.     aeErr := AEGetParamPtr(msg,
  743.                            kVUAESrvcName,
  744.                            typeChar,
  745.                            actualType,
  746.                            VUStr255ToPtr(serviceName),
  747.                            255,
  748.                            actualSize);
  749.  
  750.     IF aeErr <> noErr THEN
  751.         ReportError(aeErr, 1);
  752.     ELSE
  753.         BEGIN
  754.             serviceName[0] := CHAR(actualSize);
  755.             vuEventClass := kVUAETool;
  756.             aeErr := AEPutAttributePtr(reply,
  757.                                         keyEventClassAttr,
  758.                                         typeType,
  759.                                         @vuEventClass,
  760.                                         SIZEOF(OSType));
  761.                                         
  762.             IF aeErr <> noErr THEN ReportError(aeErr, 2);
  763.             
  764.             VUServiceHandler := errAEUnknownService;
  765.             
  766.             IF (relstring(serviceName, 'Initialize', false, true) = 0) THEN
  767.                 VUServiceHandler := VUInitializeHandler(msg, reply, refcon)
  768.             ELSE
  769.             IF (relstring(serviceName, 'Cancel', false, true) = 0) THEN
  770.                 VUServiceHandler := VUCancelHandler(msg, reply, refcon)
  771.             ELSE
  772.             IF (relstring(serviceName, 'GetToolServices', false, true) = 0) THEN
  773.                 VUServiceHandler := VUSrvcListHandler(msg, reply, refcon)
  774.             ELSE
  775.             IF (relstring(serviceName, 'GetToolVersion', false, true) = 0) THEN
  776.                 VUServiceHandler := VUVersionHandler(msg, reply, refcon)
  777.             ELSE
  778.             IF (relstring(serviceName, 'ServiceSupported', false, true) = 0) THEN
  779.                 VUServiceHandler := VUHasSrvcHandler(msg, reply, refcon)
  780.             ELSE
  781.             IF (relstring(serviceName, 'Quit', false, true) = 0) THEN
  782.                 VUServiceHandler := VUQuitHandler(msg, reply, refcon)
  783.             ELSE
  784.             IF (relstring(serviceName, 'YourService', false, true) = 0) THEN
  785.                 VUServiceHandler := YourService(msg, reply, refcon)
  786.             ELSE
  787.                 BEGIN
  788.                     ReportError(aeErr, 1984);
  789.                 END;
  790.                 
  791.         END;
  792. END;
  793.  
  794.  
  795. PROCEDURE InitAEStuff;
  796. {
  797.     Initialization of the Apple Event Manager and dispatch table.
  798.     If we don't have Apple Events or installation of any of the
  799.     Apple Event handlers fails, the program is simply terminated.
  800.     The routine starts by installing standard handlers for the
  801.     core Apple Events. This is followed by installation of the
  802.     event handlers for the V.U. 2.0 external tool interface.
  803. }
  804. VAR
  805.     response: LONGINT;
  806.     aeErr    : OSErr;
  807. BEGIN
  808.     hasAE := Gestalt(gestaltAppleEventsAttr, response) = noErr;
  809.     IF hasAE THEN BEGIN
  810.         aeErr := AEInstallEventHandler(kCoreEventClass,
  811.                                        kAEOpenApplication,
  812.                                        @AEOpenHandler,
  813.                                        0, FALSE);
  814.         IF aeErr <> noErr THEN ExitToShell;
  815.         aeErr := AEInstallEventHandler(kCoreEventClass,
  816.                                        kAEOpenDocuments,
  817.                                        @AEOpenDocHandler,
  818.                                        0, FALSE);
  819.         IF aeErr <> noErr THEN ExitToShell;
  820.         aeErr := AEInstallEventHandler(kCoreEventClass,
  821.                                        kAEQuitApplication,
  822.                                        @AEQuitHandler,
  823.                                        0, FALSE);
  824.         IF aeErr <> noErr THEN ExitToShell;
  825.         aeErr := AEInstallEventHandler(kCoreEventClass,
  826.                                        kAEPrintDocuments,
  827.                                        @AEPrintHandler,
  828.                                        0, FALSE);
  829.         IF aeErr <> noErr THEN ExitToShell;
  830.         aeErr := AEInstallEventHandler(kVUAETool,
  831.                                        kVUAESendService,
  832.                                        @VUServiceHandler,
  833.                                        0, FALSE);
  834.         IF aeErr <> noErr THEN ExitToShell;
  835.         aeErr := AESetInteractionAllowed(kAEInteractWithAll);
  836.         IF aeErr <> noErr THEN ExitToShell;
  837.         END
  838.     ELSE BEGIN
  839.         ExitToShell;
  840.     END {--if};
  841. END {InitAEStuff};
  842.  
  843.  
  844. PROCEDURE BuildMenuBar;
  845. {
  846.     Construct a menu bar for our application. (Yawn)
  847. }
  848. BEGIN
  849.     theMenuBar := GetNewMBar(kMBarID);
  850.     SetMenuBar(theMenuBar);
  851.     appleMenu := GetMHandle(kAppleMenu);
  852.     fileMenu := GetMHandle(kFileMenu);
  853.     editMenu := GetMHandle(kEditMenu);
  854.     AddResMenu(appleMenu, 'DRVR');
  855.     DrawMenuBar;
  856. END {BuildMenuBar};
  857.  
  858.  
  859. PROCEDURE InitProgram;
  860. {
  861.     Initialize the Macintoshâ„¢ Toolbox and application
  862.     environment.
  863. }
  864. BEGIN
  865.     quitting := FALSE;
  866.     background := FALSE;
  867.     MaxApplZone;
  868.     InitGraf(Ptr(@thePort));
  869.     InitFonts;
  870.     InitWindows;
  871.     InitMenus;
  872.     TEInit;
  873.     InitDialogs(NIL);
  874.     InitCursor;
  875.     
  876.     InitAEStuff;
  877.     InitializeServiceArray;
  878.     BuildMenuBar;
  879. END {InitProgram};
  880.  
  881.  
  882. PROCEDURE MainEventLoop;
  883. {
  884.     Main event loop. Just get events, and dispatch them to an
  885.     appropriate handler until we get the 'quit' command.
  886. }
  887. BEGIN
  888.     REPEAT
  889.         IF WaitNextEvent(everyEvent, theEvent, 30, NIL) THEN
  890.             CASE theEvent.what OF
  891.                 nullEvent: Idling;
  892.                 mouseDown: DispatchMouseDown(theEvent);
  893.                 keyDown, autoKey: DispatchKeyDown(theEvent);
  894.                 activateEvt: ActivateWindow(WindowPtr(theEvent.message),
  895.                                             BAND(theEvent.modifiers, activeFlag) <> 0);
  896.                 updateEvt: UpdateWindow(WindowPtr(theEvent.message));
  897.                 diskEvt: DiskInserted(theEvent.message);
  898.                 osEvt: DispatchOSEvent(theEvent);
  899.                 kHighLevelEvent: DispatchHighEvent(theEvent);
  900.             END;
  901.     UNTIL quitting;
  902. END {MainEventLoop};
  903.  
  904. BEGIN
  905.     InitProgram;
  906.     MainEventLoop;
  907. END.